/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.fiap.si.graphos;

import br.com.fiap.si.graphos.ExecucaoGrapho.VertexFactory;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.io.GraphMLMetadata;
import edu.uci.ics.jung.io.GraphMLReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

import edu.ucla.sspace.common.Similarity;
import edu.ucla.sspace.lsa.LatentSemanticAnalysis;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.collections15.BidiMap;
import org.apache.commons.collections15.Factory;
import org.xml.sax.SAXException;

/**
 *
 * @author lucas.rezende
 */
public class ExecucaoGrapho {

    public ArrayList<String> verticesVisitados = new ArrayList<String>();
    public ArrayList<String> arestasVisitadas = new ArrayList<String>();
    public node verticeInicial;
    public node verticeAtual;

    public void IniciarExecucao() throws ParserConfigurationException, SAXException, IOException {

        Locale.setDefault(new Locale("en", "US"));

        //Step 1 we make a new GraphML Reader. We want an Undirected Graph of type node and edge.
        GraphMLReader<DirectedSparseMultigraph<node, edge>, node, edge> gmlr =
                new GraphMLReader<DirectedSparseMultigraph<node, edge>, node, edge>(new VertexFactory(), new EdgeFactory());

        //Next we need a Graph to store the data that we are reading in from GraphML. This is also an Undirected Graph
        // because it needs to match to the type of graph we are reading in.
        final DirectedSparseMultigraph<node, edge> graph = new DirectedSparseMultigraph<node, edge>();

        //FileChooser para selecionar o arquivo XML
        JFileChooser chooser = new JFileChooser();
        String caminhoArquivo = "";
        int retorno = chooser.showOpenDialog(null);
        if (retorno == JFileChooser.APPROVE_OPTION) {
            caminhoArquivo = chooser.getSelectedFile().getAbsolutePath();
        }
        if (!caminhoArquivo.equals("")) {
            FileReader in = new FileReader(caminhoArquivo);
            gmlr.load(in, graph); //Here we read in our graph. filename is our .graphml file, and graph is where we
            // will store our graph.

            BidiMap<node, String> vertex_ids = gmlr.getVertexIDs();  //The vertexIDs are stored in a BidiMap.
            Map<String, GraphMLMetadata<edge>> edge_meta = gmlr.getEdgeMetadata(); // Our edge Metadata is stored in a map.
            Map<String, GraphMLMetadata<node>> vertex_desc = gmlr.getVertexMetadata(); //Our vertex Metadata is stored in a map.

            // Here we iterate through our vertices, n, and we set the value and the color of our nodes from the data we have
            // in the vertex_ids map and vertex_color map.
            for (node n : graph.getVertices()) {
                n.setValue(vertex_ids.get(n)); //Set the value of the node to the vertex_id which was read in from the GraphML Reader.
                n.setDescription(vertex_desc.get("descricao").transformer.transform(n)); // Set the color, which we get from the Map, vertex_color.

                //Let's print out the data so we can get a good understanding of what we've got going on.
                System.out.println("ID: " + n.getID() + ", Value: " + n.getValue() + ", Descricao: " + n.getDescription());
                if (n.getDescription().equals("Inicio")) {
                    verticeInicial = n;
                }
            }
            // Just as we added the vertices to the graph, we add the edges as well.
            for (edge e : graph.getEdges()) {
                e.setValue(edge_meta.get("respostas").transformer.transform(e)); //Set the edge's value.
                System.out.println("Edge ID: " + e.getValue());
            }

            verticeAtual = verticeInicial;

            do {
                Collection<node> verticesSucessores = graph.getSuccessors(verticeAtual);
                String perg = JOptionPane.showInputDialog(null, "Agente says: " + verticeAtual.getValue());

                for (node vertice : verticesSucessores) {
                    LatentSemanticAnalysis lsa = new LatentSemanticAnalysis();
                    lsa.processDocument(new BufferedReader(new StringReader(perg.toLowerCase())));

                    Collection<edge> arestas = graph.findEdgeSet(verticeAtual, vertice);
                    for (edge e : arestas) {

                        String[] respostas = e.mValue.split(";");
                        for (String r : respostas) {
                            lsa.processDocument(new BufferedReader(new StringReader(r.toLowerCase())));
                        }
                    }

                    //configurações do algoritmo	
                    Properties prop = new Properties();
                    prop.setProperty("edu.ucla.sspace.lsa.LatentSemanticAnalysis.retainDocSpace", "true");

                    lsa.processSpace(prop); //esta linha executa a formação da LSA 

                    //abaixo o rank de comparação. Veja que foi comparado o documento 3 com os demais, já que 3 é a frase do usuário
                    for (int i = 0; i < lsa.getVectorLength(); i++) {

                        // faz o calculo da similaridade.
                        double similaridade = Similarity.cosineSimilarity(lsa.getDocumentVector(i), lsa.getDocumentVector(0));

                        //debug, mostrar o valor da similaridade.
                        System.out.print("---> grau semelhança entre docs 3 e " + i + " é: " + similaridade);
                        System.out.println();
                        
                        if (similaridade > 0.9) {
                            verticeAtual = vertice;
                            if (verticeAtual.getDescription().equals("Fim")) {
                                JOptionPane.showMessageDialog(null, "Agente says: " + verticeAtual.getValue());
                            }
                        }
                    }

                }
            } while (!verticeAtual.getDescription().equals("Fim"));
        }
    }

    public class node {

        private final int mID;
        private String mValue;
        private String mDescription;

        public node(int x) {
            mID = x;
        }

        public int getID() {
            return mID;
        }

        public void setValue(String value) {
            this.mValue = value;
        }

        public String getValue() {
            return (mValue);
        }

        public void setDescription(String description) {
            mDescription = description;
        }

        public String getDescription() {
            return (mDescription);
        }

        public String toString() {
            return (this.getValue());
        }
    }

    public class edge {

        private final int mID;
        private String mValue;

        public edge(int x) {
            mID = x;
        }

        public int getID() {
            return mID;
        }

        public void setValue(String mValue) {
            this.mValue = mValue;
        }

        public String getValue() {
            return mValue;
        }
    }

// This class simply makes a factory for our vertices. The create() function makes a new vertex and increments n, so that
// each node will have a different id. Check the node class's constructor.
    class VertexFactory implements Factory {

        private int n = 0;

        public node create() {
            return (new node(n++));
        }
    }

// This class simply makes a factory for our edges. The create() function makes a new edge and increments e, so that
// each edge will have a different id. Check the edge class's constructor.
    class EdgeFactory implements Factory {

        private int e = 0;

        public edge create() {
            return (new edge(e++));
        }
    }
}
